package utils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;

import model.DATAError;
import model.EA2ExcelMapping;

import org.sparx.Diagram;
import org.sparx.Element;
import org.sparx.Package;
import org.sparx.Repository;

public class ControllerUtils {

	public static Object propertyGetter(Object obj, String fieldName) {

		Class<?> cls = obj.getClass();
		// for (Field fld : cls.getDeclaredFields()) {
		// fld.setAccessible(true);
		// if (Modifier.isPrivate(fld.getModifiers())) {
		// try {
		// if (fld.get(obj) == null) {
		// isNotNull = false;
		// break;
		// }
		// } catch (IllegalArgumentException e) {
		// e.printStackTrace();
		// } catch (IllegalAccessException e) {
		// e.printStackTrace();
		// }
		// }
		//
		// }
		try {
			Field f = cls.getDeclaredField(fieldName);
			f.setAccessible(true);
			return f.get(obj);

		} catch (NoSuchFieldError | NoSuchFieldException | SecurityException
				| IllegalArgumentException | IllegalAccessException ex) {
			MessageHandler
					.getMessageHandler()
					.getErrors()
					.add(new DATAError(obj.getClass().getCanonicalName(), ex
							.getMessage()));

		}
		return null;
	}

	/*
	 * First object is instantiated object second is method name - always string
	 * third and further can be objects with different types
	 */
	public static void methodExecutor(Object[] args) {
		if (args.length < 6) {

			String methodName = String.valueOf(args[1]);

			try {
				Object[] ttt = Arrays.copyOfRange(args, 2, args.length);
				Class<?> mainClass = args[0].getClass();
				for (Method mtd : mainClass.getDeclaredMethods()) {
					mtd.setAccessible(true);
					if (mtd.getName().equals(methodName)) {
						mtd.invoke(args[0], ttt);
					}
				}

			} catch (SecurityException | IllegalAccessException
					| IllegalArgumentException | InvocationTargetException e) {
				MessageHandler.getMessageHandler().getErrors()
						.add(new DATAError("Error ", e.getMessage()));
				MessageHandler.getMessageHandler().ShowErrors();
				e.printStackTrace();
			}
		} else {
			MessageHandler.getMessageHandler().getErrors()
					.add(new DATAError("Error ", "Too many Arguments"));
			MessageHandler.getMessageHandler().ShowErrors();
		}
	}

	/**
	 * 
	 * @param Parent
	 * @param ObjectsName
	 * @param objectType
	 *            dieser Parameter mit Folgendem template konfiguriert werden
	 *            muss
	 */

	public static void createEAObject(Object Parent, String ObjectsName,
			String objectType) {
		if (Parent instanceof org.sparx.Package) {
			if (objectType.toLowerCase().contains("package")) {
				Package par = (Package) Parent;
				par.GetPackages().AddNew(ObjectsName, "Package");
				par.GetPackages().Refresh();
			}
			if (objectType.toLowerCase().contains("class")) {
				Package par = (Package) Parent;
				org.sparx.Collection<Element> elts = par.GetElements();
				Element elt = elts.AddNew(ObjectsName, "Class");
				elt.Update();
				elts.Refresh();
			}
			if (objectType.toLowerCase().contains("diagram")) {
				if (objectType.contains("activity")) {
					Package par = (Package) Parent;
					org.sparx.Collection<Diagram> diags = par.GetDiagrams();
					Diagram diag = diags.AddNew(ObjectsName, "Activity");
					diag.Update();
					diags.Refresh();
				}
				if (objectType.toLowerCase().contains("class")) {
					Package par = (Package) Parent;
					par.GetDiagrams().AddNew(ObjectsName, "Class");

					par.GetDiagrams().Refresh();
				}

			}

		} else {
			System.out.println("Unsupported object type");

		}

	}

	public static org.sparx.Repository connectEA(String fileName) {
		Repository rep = new Repository();

		if (FileUtils.exist(fileName)) {
			if (rep.OpenFile(fileName)) {
				return rep;
			} else {
				return null;
			}
		} else {
			System.err.println("Cannot open file");
			return null;
		}
	}

	/**
	 * 
	 * @param rep
	 *            repository to make navigation upon
	 * @param xPath
	 *            now direkt name path to current package ex.
	 *            "/<ModelName>/<package1>/<package2>"
	 * @return the package that is an aim of xpath
	 */
	public static org.sparx.Package XPath(Repository rep, String xPath) {

		String[] xPathArray = StringUtils.splitBy(xPath, '/');
		// TODO: Remove after ok
		for (int k = 0; k < xPathArray.length; k++) {
			System.out.println("Splitted xPath: " + xPathArray[k]);
		}
		System.out.println();
		if (rep != null && !xPath.isEmpty()) {

			org.sparx.Package root = rep.GetModels().GetAt((short) 0);

			for (int i = 0; i < xPathArray.length; i++) {
				// Throws index out of bounds
				if (root != null) {
					root = getNextPackage(root, xPathArray[i]);
				} else {
					System.out.println("Fehler! Keine Package ist gefunden ");
					break;
				}
			}
			return root;

		}

		return null;

	}

	public static void disconnectEA(Repository rep) {
		rep.CloseFile();
	}

	private static org.sparx.Package getNextPackage(Package parent,
			String nextName) {
		try {
			Package pak1 = parent.GetPackages().GetByName(nextName);
			System.out.println(pak1.GetName());
			System.out.println(pak1.GetNotes());
			return parent.GetPackages().GetByName(nextName);
		} catch (Exception ex) {
			return null;
		}

		// return parent.GetPackages().GetByName(nextName);

	}

	public static void clearAllElements(org.sparx.Package pak) {
		if (pak != null) {
			org.sparx.Collection<org.sparx.Element> elements = pak
					.GetElements();
			ArrayList<org.sparx.Element> ll = new ArrayList<Element>();

			for (int i = 0; i < elements.GetCount(); i++) {
				elements.Delete((short) i);
			}

		}
	}

	public static void main(String[] args) {

		EA2ExcelMapping dd = new EA2ExcelMapping("ggle", 23);

		System.out.println(String.valueOf(propertyGetter(dd, "EAElementType")));
		Object[] objectNamearguments = new Object[] { dd, "printDumm",
				"carlos", 12, 345 };
		methodExecutor(objectNamearguments);
		// Class<?> cl = "hello".getClass();
	}
}
